<%!

  Copyright (c) Facebook, Inc. and its affiliates.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

%><%#service:functions%><%#function:returnType%><%^function:starts_interaction?%>
template <typename ProtocolIn_, typename ProtocolOut_>
void <%service:parent_service_name%>AsyncProcessor::setUpAndProcess_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>(apache::thrift::ResponseChannelRequest::UniquePtr req, apache::thrift::SerializedRequest&& serializedRequest, apache::thrift::Cpp2RequestContext* ctx, folly::EventBase* eb, apache::thrift::concurrency::ThreadManager* tm) {
  if (!setUpRequestProcessing(req, ctx, eb, <%^function:eb%>tm<%/function:eb%><%#function:eb%>nullptr<%/function:eb%>, <% > types/function_kind%>, iface_<%#service:interaction?%>, "<%service:name%>"<%/service:interaction?%>)) {
    return;
  }
<%^function:eb%>
  auto pri = iface_->getRequestPriority(ctx, apache::thrift::concurrency::<%function:priority%>);
  processInThread(std::move(req), std::move(serializedRequest), ctx, eb, tm, pri, <% > types/function_kind%>, &<%service:parent_service_name%>AsyncProcessor::process_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%><ProtocolIn_, ProtocolOut_>, this);
<%/function:eb%><%#function:eb%>
  process_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%><ProtocolIn_, ProtocolOut_>(std::move(req), std::move(serializedRequest), ctx, eb, tm);
<%/function:eb%>
}

template <typename ProtocolIn_, typename ProtocolOut_>
void <%service:parent_service_name%>AsyncProcessor::process_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>(apache::thrift::ResponseChannelRequest::UniquePtr req, apache::thrift::SerializedRequest&& serializedRequest, apache::thrift::Cpp2RequestContext* ctx, folly::EventBase* eb, apache::thrift::concurrency::ThreadManager* tm) {
  // make sure getConnectionContext is null
  // so async calls don't accidentally use it
  iface_->setConnectionContext(nullptr);
  <%service:parent_service_name%>_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>_pargs args;
<%#function:args%><%#field:type%>
<%^type:resolves_to_complex_return?%>
<%^type:enum?%>
  <% > types/type%> uarg_<%field:cpp_name%>{0};
<%/type:enum?%>
<%#type:enum?%>
  <% > types/type%> uarg_<%field:cpp_name%>{static_cast<<% > types/type%>>(0)};
<%/type:enum?%>
  args.get<<%field:index%>>().value = &uarg_<%field:cpp_name%>;
<%/type:resolves_to_complex_return?%>
<%#type:resolves_to_complex_return?%>
  <%#function:stack_arguments?%>
  <% > types/type%> uarg_<%field:cpp_name%>;
  args.get<<%field:index%>>().value = &uarg_<%field:cpp_name%>;
  <%/function:stack_arguments?%>
  <%^function:stack_arguments?%>
  auto uarg_<%field:cpp_name%> = std::make_unique<<% > types/type%>>();
  args.get<<%field:index%>>().value = uarg_<%field:cpp_name%>.get();
  <%/function:stack_arguments?%>
<%/type:resolves_to_complex_return?%>
<%/field:type%><%/function:args%>
  std::unique_ptr<apache::thrift::ContextStack> ctxStack(this->getContextStack(this->getServiceName(), "<%service:parent_service_name%>.<%#service:interaction?%><%service:name%>.<%/service:interaction?%><%function:name%>", ctx));
<%#service:interaction?%>
  auto tile = ctx->getTile();
<%/service:interaction?%>
  try {
    deserializeRequest<ProtocolIn_>(args, ctx->getMethodName(), serializedRequest, ctxStack.get());
  }
  catch (const std::exception& ex) {
<%#function:oneway?%>
    LOG(ERROR) << ex.what() << " in function <%function:name%>";
    eb->runInEventBaseThread([req = std::move(req)] {});
    return;
  }
  auto callback = std::make_unique<apache::thrift::HandlerCallbackBase>(std::move(req), std::move(ctxStack), nullptr, eb, tm, ctx<%#service:interaction?%>, tile<%/service:interaction?%>);
<%/function:oneway?%>
<%^function:oneway?%>
    apache::thrift::detail::ap::process_handle_exn_deserialization<ProtocolOut_>(
        ex, std::move(req), ctx, eb, "<%#service:interaction?%><%service:name%>.<%/service:interaction?%><%function:name%>");
    return;
  }
  req->setStartedProcessing();
  auto callback = std::make_unique<apache::thrift::HandlerCallback<<% > types/unique_ptr_type%>>>(std::move(req), std::move(ctxStack), return_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%><ProtocolIn_,ProtocolOut_>, throw_wrapped_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%><ProtocolIn_, ProtocolOut_>, ctx->getProtoSeqId(), eb, tm, ctx<%!
  %><%#type:stream_or_sink?%>, <%^function:eb%>apache::thrift::ServerInterface::getBlockingThreadManager(tm)<%/function:eb%><%#function:eb%>eb<%/function:eb%><%/type:stream_or_sink?%><%!
  %><%#service:interaction?%><%^type:stream_or_sink?%><%^type:void?%>, nullptr<%/type:void?%><%/type:stream_or_sink?%>, tile<%/service:interaction?%>);
<%^function:eb%>
  if (!callback->isRequestActive()) {
    return;
  }
<%/function:eb%>
<%/function:oneway?%>
  <%^service:interaction?%>iface_<%/service:interaction?%><%#service:interaction?%>static_cast<<%service:parent_service_name%>SvIf::<%service:name%>If*>(tile)<%/service:interaction?%>-><%#function:eb%>async_eb<%/function:eb%><%^function:eb%>async_tm<%/function:eb%>_<%function:cpp_name%>(std::move(callback)<% > service_tcc/get_args_ref%>);
}

<%^function:oneway?%>
template <class ProtocolIn_, class ProtocolOut_>
<%#type:void?%>
folly::IOBufQueue <%service:parent_service_name%>AsyncProcessor::return_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>(int32_t protoSeqId, apache::thrift::ContextStack* ctx) {
<%/type:void?%>
<%^type:void?%>
    <%^type:streamresponse?%><%^type:sink?%>
folly::IOBufQueue <%service:parent_service_name%>AsyncProcessor::return_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>(int32_t protoSeqId, apache::thrift::ContextStack* ctx, <% > types/type%> const& _return) {
    <%/type:sink?%><%/type:streamresponse?%>
    <%#type:streamresponse?%>
apache::thrift::ResponseAndServerStreamFactory <%service:parent_service_name%>AsyncProcessor::return_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>(int32_t protoSeqId, apache::thrift::ContextStack* ctx, folly::Executor::KeepAlive<> executor, <% > types/type%> _return) {
    <%/type:streamresponse?%>
    <%#type:sink?%>
std::pair<folly::IOBufQueue, apache::thrift::detail::SinkConsumerImpl> <%service:parent_service_name%>AsyncProcessor::return_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>(apache::thrift::ContextStack* ctx, <% > types/type%>&& _return, folly::Executor::KeepAlive<> executor) {
    <%/type:sink?%>
<%/type:void?%>
  ProtocolOut_ prot;
<%#function:returns_stream?%>
  <%service:parent_service_name%>_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>_presult::FieldsType result;
  using StreamPResultType = <%service:parent_service_name%>_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>_presult::StreamPResultType;
      <%#type:streamHasFirstResponse?%>
  result.get<0>().value = const_cast<<% > types/type%>::ResponseType*>(&_return.response);
  result.setIsSet(0, true);
  auto& _returnStream = _return.stream;
      <%/type:streamHasFirstResponse?%>
      <%^type:streamHasFirstResponse?%>
  auto& _returnStream = _return;
      <%/type:streamHasFirstResponse?%>

      <%^function:stream_exceptions?%>
      using ExMapType = apache::thrift::detail::ap::EmptyExMapType;
      <%/function:stream_exceptions?%>
      <%#function:stream_exceptions?%>
  struct ExMapType {
    bool operator()(StreamPResultType& res, folly::exception_wrapper ew) {
      <%#function:stream_exceptions%>
      if (ew.with_exception([&](<%#field:type%><% > common/type_namespace_cpp2%><%type:name%><%/field:type%>& e) {
            res.get<<%field:index_plus_one%>>().ref() = e;
            res.setIsSet(<%field:index_plus_one%>, true);
          })) {
        return true;
      }
      <%/function:stream_exceptions%>
      return false;
    }
  };
      <%/function:stream_exceptions?%>
  auto _encodedStream = apache::thrift::detail::ap::encode_server_stream<ProtocolOut_, StreamPResultType, ExMapType>(std::move(_returnStream), std::move(executor));
  return {serializeResponse("<%#service:interaction?%><%service:name%>.<%/service:interaction?%><%function:name%>", &prot, protoSeqId, ctx, result), std::move(_encodedStream)};
<%/function:returns_stream?%>
<%#function:returns_sink?%>
  <%service:parent_service_name%>_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>_presult::FieldsType result;
  using SinkPResultType = <%service:parent_service_name%>_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>_presult::SinkPResultType;
  using FinalResponsePResultType = <%service:parent_service_name%>_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>_presult::FinalResponsePResultType;
  <%#type:sinkHasFirstResponse?%>
  result.get<0>().value = &_return.response;
  result.setIsSet(0, true);
  <%/type:sinkHasFirstResponse?%>

  <%^function:sink_final_response_exceptions?%>
  using ExMapType = apache::thrift::detail::ap::EmptyExMapType;
  <%/function:sink_final_response_exceptions?%>
  <%#function:sink_final_response_exceptions?%>
  struct ExMapType {
    bool operator()(FinalResponsePResultType& res, folly::exception_wrapper ew) {
      <%#function:sink_final_response_exceptions%>
      if (ew.with_exception([&](<%#field:type%><% > common/type_namespace_cpp2%><%type:name%><%/field:type%>& e) {
            res.get<<%field:index_plus_one%>>().ref() = e;
            res.setIsSet(<%field:index_plus_one%>, true);
          })) {
        return true;
      }
      <%/function:sink_final_response_exceptions%>
      return false;
    }
  };
  <%/function:sink_final_response_exceptions?%>

  auto sinkConsumerImpl = apache::thrift::detail::ap::toSinkConsumerImpl<
      ProtocolIn_,
      ProtocolOut_,
      SinkPResultType,
      FinalResponsePResultType,
      ExMapType>(
  <%#type:sinkHasFirstResponse?%>
      std::move(_return.sinkConsumer),
  <%/type:sinkHasFirstResponse?%>
  <%^type:sinkHasFirstResponse?%>
      std::move(_return),
  <%/type:sinkHasFirstResponse?%>
      std::move(executor));

  return {serializeResponse("<%#service:interaction?%><%service:name%>.<%/service:interaction?%><%function:name%>", &prot, 0, ctx, result), std::move(sinkConsumerImpl)};
<%/function:returns_sink?%>
<%^function:returns_stream?%><%^function:returns_sink?%>
  <%service:parent_service_name%>_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>_presult result;
<%^type:void?%>
  result.get<0>().value = const_cast<<% > types/type%>*>(&_return);
  result.setIsSet(0, true);
<%/type:void?%>
  return serializeResponse("<%#service:interaction?%><%service:name%>.<%/service:interaction?%><%function:name%>", &prot, protoSeqId, ctx, result);
<%/function:returns_sink?%><%/function:returns_stream?%>
}

template <class ProtocolIn_, class ProtocolOut_>
void <%service:parent_service_name%>AsyncProcessor::throw_wrapped_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>(apache::thrift::ResponseChannelRequest::UniquePtr req,int32_t protoSeqId,apache::thrift::ContextStack* ctx,folly::exception_wrapper ew,apache::thrift::Cpp2RequestContext* reqCtx) {
  if (!ew) {
    return;
  }
<%#function:exceptions?%>
  <%service:parent_service_name%>_<%#service:interaction?%><%service:name%>_<%/service:interaction?%><%function:cpp_name%>_presult result;
<%/function:exceptions?%>
<%#function:exceptions%>
  if (ew.with_exception([&](<%#field:type%><% > common/type_namespace_cpp2%><%type:name%><%/field:type%>& e) {
    ctx->userExceptionWrapped(true, ew);
<%#type:void?%>
    result.get<<%field:index%>>().ref() = e;
    result.setIsSet(<%field:index%>, true);
<%/type:void?%>
<%^type:void?%>
  <%^function:returns_stream?%><%^function:returns_sink?%>
    result.get<<%field:index_plus_one%>>().ref() = e;
    result.setIsSet(<%field:index_plus_one%>, true);
  <%/function:returns_sink?%><%/function:returns_stream?%>
  <%#function:returns_stream?%>
  <%#type:streamHasFirstResponse?%>
    result.fields.get<<%field:index_plus_one%>>().ref() = e;
    result.fields.setIsSet(<%field:index_plus_one%>, true);
  <%/type:streamHasFirstResponse?%>
  <%^type:streamHasFirstResponse?%>
    result.fields.get<<%field:index%>>().ref() = e;
    result.fields.setIsSet(<%field:index%>, true);
  <%/type:streamHasFirstResponse?%>
  <%/function:returns_stream?%>
  <%#function:returns_sink?%>
  <%#type:sinkHasFirstResponse?%>
    result.fields.get<<%field:index_plus_one%>>().ref() = e;
    result.fields.setIsSet(<%field:index_plus_one%>, true);
  <%/type:sinkHasFirstResponse?%>
  <%^type:sinkHasFirstResponse?%>
    result.fields.get<<%field:index%>>().ref() = e;
    result.fields.setIsSet(<%field:index%>, true);
  <%/type:sinkHasFirstResponse?%>
  <%/function:returns_sink?%>
<%/type:void?%>
  }
  )) {} else
<%/function:exceptions%>
  {
    (void)protoSeqId;
    apache::thrift::detail::ap::process_throw_wrapped_handler_error<ProtocolOut_>(
        ew, std::move(req), reqCtx, ctx, "<%#service:interaction?%><%service:name%>.<%/service:interaction?%><%function:name%>");
    return;
  }
<%#function:exceptions?%>
  ProtocolOut_ prot;
  <%^function:returns_stream?%><%^function:returns_sink?%>
  auto queue = serializeResponse("<%#service:interaction?%><%service:name%>.<%/service:interaction?%><%function:name%>", &prot, protoSeqId, ctx, result);
  queue.append(apache::thrift::transport::THeader::transform(queue.move(), reqCtx->getHeader()->getWriteTransforms()));
  return req->sendReply(queue.move());
  <%/function:returns_sink?%><%/function:returns_stream?%>
  <%#function:returns_stream?%>
  auto queue = serializeResponse("<%#service:interaction?%><%service:name%>.<%/service:interaction?%><%function:name%>", &prot, protoSeqId, ctx, result.fields);
  queue.append(apache::thrift::transport::THeader::transform(queue.move(), reqCtx->getHeader()->getWriteTransforms()));
  std::ignore = req->sendStreamReply(queue.move(), apache::thrift::StreamServerCallbackPtr(nullptr));
  <%/function:returns_stream?%>
  <%#function:returns_sink?%>
  auto queue = serializeResponse("<%#service:interaction?%><%service:name%>.<%/service:interaction?%><%function:name%>", &prot, protoSeqId, ctx, result.fields);
  queue.append(apache::thrift::transport::THeader::transform(queue.move(), reqCtx->getHeader()->getWriteTransforms()));
  req->sendSinkReply(queue.move(), {});
  <%/function:returns_sink?%>
<%/function:exceptions?%>
}

<%/function:oneway?%>
<%/function:starts_interaction?%><%/function:returnType%><%/service:functions%>
